home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Languages / MacQForth 1.0 / documentation / Lessons / LESSON 3 < prev    next >
Encoding:
Text File  |  1995-03-23  |  14.7 KB  |  230 lines  |  [TEXT/ALFA]

  1.  
  2. LESSON 3            "Using variables, constants and memory"
  3. --------------------------------------------------------------------------------
  4.  
  5.    Contents of this lesson:
  6.    
  7.                1.  VARIABLE, CONSTANT and CREATE
  8.                2.  Strings
  9.                3.  Word summary
  10.                4.  Exercises
  11.                
  12. ================================================================================
  13.                
  14.    Forth variables, constants and memory is the subject of this lesson.  
  15.    Here one learns how to preserve values and how to create simple data 
  16.    structures in memory.
  17.    
  18.    
  19.    
  20. VARIABLE, CONSTANT and CREATE
  21. -----------------------------
  22.  
  23.    As a Forth program is compiled it builds its dictionary.  User defined 
  24.    colon definitions go in the dictionary, as do places to store data.  
  25.    Forth provides two special purpose words for creating named variables 
  26.    and constants and one general purpose word for reserving dictionary 
  27.    space.
  28.    
  29.    
  30.    VARIABLE
  31.    --------
  32.    
  33.    We know that a value can be pulled off the data stack and placed on 
  34.    the return stack for temporary storage, but how to we preserve a value 
  35.    indefinitely?  For that Forth provides the word VARIABLE.  VARIABLE 
  36.    takes the next token in the input stream and creates a special 
  37.    dictionary entry with that name.  VARIABLE also reserves memory for 
  38.    one stack entry (either 16 or 32 bits) and compiles code to push the 
  39.    address of this location on the stack when executed.  In some Forth 
  40.    versions VARIABLE needs a value on the stack to initialize the 
  41.    variable.  MacQForth does not need a value on the stack and the 
  42.    contents of a variable must be initialize by hand (as is the case in 
  43.    most programming languages).
  44.    
  45.    E.g.
  46.    
  47.    variable age   ( create a variable called 'age' )
  48.    
  49.    28 age !       ( ! expects a value and an address, it then places that )
  50.                   ( value in that address                                 )
  51.                   
  52.    age @ .        ( @ expects an address and gets the value at that address ) 
  53.                   ( placing it on the stack                               )
  54.    
  55.    
  56.    There are several things to note in this simple example:
  57.    
  58.        (1)  VARIABLE creates a dictionary entry, like : , so it cannot
  59.             be used from within a definition.
  60.        (2)  A variable pushes its _address_ in memory on the stack when
  61.             referenced.  This is contrary to most programming languages 
  62.             which return the variable's _value_ when referenced.  Some 
  63.             Forths include a type VALUE that acts in this way.
  64.        (3)  The words ! and @ deal with 16- or 32-bit words (depending on 
  65.             whether the Forth is a 16-bit or 32-bit Forth).  So,  if the 
  66.             variable AGE is at location 16543, then the next 8-bits of 
  67.             AGE's value are at location 16544.  Unlike C, adding 1 to a 
  68.             pointer (an address) in Forth simply adds 1 to the address.
  69.             
  70.    Generally, beginning Forth programmers are discouraged from using too 
  71.    many variables.  This is because some consider it a matter of skill 
  72.    to use as few as possible, but also because all variables are global 
  73.    in Forth, i.e. once defined any word defined after the variable can use 
  74.    it.  This can lead to some frustrating bugs if too many are used.
  75.    
  76.    What if I want to access individual bytes?
  77.    
  78.    Then use C@ and C! in place of @ and ! .  Naturally, if one attempts 
  79.    to store a number greater than 255 in a single byte only the lower 
  80.    8-bits of the value will be stored.
  81.    
  82.    To review:
  83.    
  84.      Memory access in Forth uses the words @, !, C@, and C! with stack 
  85.      effects:
  86.      
  87.          @  ( addr -- value )  return the 16 or 32-bit value at address
  88.          !  ( value addr -- )  store value (16 or 32-bits) at address
  89.         C@  ( addr -- value )  return the byte value (8-bits) at address
  90.         C!  ( value addr -- )  store value (<256) at the address
  91.         
  92.    So,
  93.    
  94.    ( assuming a 32-bit Forth )
  95.    
  96.    variable TEXT  ( reserve 4 bytes of dictionary named TEXT )
  97.    
  98.    65 TEXT C!  66 TEXT 1+ C!  67 TEXT 2+ C!  68 TEXT 3 + C!
  99.    
  100.    ( the words 1+ and 2+ add one and two to the top stack value )
  101.    
  102.    Now, what does this do?
  103.    
  104.    Creating the variable reserves 4 bytes of dictionary space, so there 
  105.    we have room for 4 8-bit characters:
  106.    
  107.    
  108.                      +-- a byte
  109.                      V
  110.                    +---+---+---+---+
  111.    dictionary ->   | 0 | 1 | 2 | 3 |
  112.                    +---+---+---+---+
  113.                      ^
  114.    address ->        16543  (start of TEXT)
  115.    
  116.    
  117.    The first byte of TEXT is at the address: 16543 = TEXT
  118.    The second byte is at the address       : 16544 = TEXT 1+
  119.    The third byte is at address            : 16545 = TEXT 2+
  120.    The last (fourth) byte is at address    : 16546 = TEXT 3 +
  121.    
  122.    Knowing that ASCII 65 = 'A' we can see that the above puts the 
  123.    characters 'ABCD' in the variable TEXT.  Normally, one uses variables 
  124.    to hold numbers and CREATE to make strings.
  125.    
  126.    
  127.    CONSTANT
  128.    --------
  129.    
  130.    Sometimes the same value is needed repeatedly within a program.  In 
  131.    such a case it is likely best to use a CONSTANT.  CONSTANT works in 
  132.    much the same way as VARIABLE: it takes the next token from the input 
  133.    stream and creates a dictionary entry with that name.  It also takes 
  134.    the top stack value and places it in the entry along with code to push 
  135.    that value on the stack when executed,
  136.    
  137.    28 constant AGE  ( create a constant called AGE )
  138.    
  139.    AGE              ( pushes 28 on the stack )
  140.    
  141.    AGE @            ( fetches the contents of location 28, normally this  ) 
  142.                     ( is only useful if the constant corresponds to a     )
  143.                     ( meaningful memory location, like a hardware address )
  144.                     
  145.    On occassion one will see something like:
  146.    
  147.    0 constant 0
  148.    1 constant 1
  149.    
  150.    While at first glance this seems rather a waste, it is done to improve 
  151.    speed.  Recall that when the interpreter/compiler encounters a token 
  152.    in the input stream it first attempts to look the token up in the dictionary 
  153.    and then if that fails it attempts to convert the token to a number.  
  154.    So, since 0 and 1 are frequently used it is slightly faster to define 
  155.    them to be a constant so that they are found in the dictionary before 
  156.    being converted to a number.
  157.    
  158.    Always remember that freedom to the programmer is the cry of Forth.  
  159.    Therefore, Forth allows the following while other languages do not:
  160.    
  161.    24 3 + .
  162.      27
  163.    
  164.    1 constant 3
  165.    
  166.    24 3 + .
  167.      25
  168.    
  169.    Yes, Forth will let you redefine a constant!  Only the oldest of FORTRAN 
  170.    compilers allowed that as far as I know.  Note, MacQForth does not 
  171.    allow this, though Mops, the Forth MacQForth was written in, does.
  172.    
  173.    
  174.    CREATE
  175.    ------
  176.    
  177.    Create takes the next token from the input stream and defines a 
  178.    dictionary entry with that name.  That is all it does.
  179.    
  180.    When combined with the word ALLOT to reserve dictionary space CREATE 
  181.    becomes quite useful:
  182.    
  183.    create AGES  8 allot
  184.    
  185.    This creates a dictionary entry called AGES and reserves 8 BYTES of 
  186.    dictionary space.  Note that ALLOT expects the number of _bytes_ to be 
  187.    reserved on the stack.  Now, suppose we wished to use AGES as an array 
  188.    to store the ages of four people, since each age is 16-bits (2 bytes) long 
  189.    we need 8 bytes for 4 ages, 4 * 2 = 8.  Using the ! and @ words plus 
  190.    offsets to the base address AGES as we did with TEXT above we can use 
  191.    this section of the dictionary as an array:
  192.    
  193.    : { ( -- ) ;  ( a do nothing word )
  194.    : } ( addr index -- addr+index*2 )  2* + ; ( 2* = 2 * but faster )
  195.    
  196.    28  AGES { 0 }  !   ( put 28 in AGES   )
  197.    27  AGES { 1 }  !   ( put 27 in AGES+2 )
  198.    29  AGES { 2 }  !   ( put 29 in AGES+4 )
  199.    30  AGES { 3 }  !   ( put 30 in AGES+6 )
  200.       
  201.    We can recover a value in much the same way:
  202.    
  203.    AGES { 2 }  @  .    ( outputs 29 )
  204.    
  205.    Now, what is going on here:
  206.    
  207.       (1)  CREATE and ALLOT reserved dictionary space and gave it a name.
  208.       (2)  } was defined to take an address and index and return the 
  209.            desired address.  The 2* was necessary since each entry was 2
  210.            bytes in length.  In a 32-bit Forth it would have been 4* .
  211.            { was defined to make the code look nicer.
  212.       (3)  Note that in true Forth form, there is no such thing as range
  213.            checking.  We could have said  33 AGES { 101 } !  and Forth would
  214.            have done it happily.  Of course, that part of the dictionary is
  215.            likely to contain data that we do not want changed.
  216.       (4)  Negative indices are allowed but not recommended for reason (3) 
  217.            above.
  218.       (5)  Note that arrays defined in this manner start at index 0, not 1.
  219.       
  220.    
  221.    Other memory access words
  222.    -------------------------
  223.    
  224.       +! ( value addr -- )  add value to the present value in addr
  225.         e.g.
  226.              3 N !  ( put 3 in N )
  227.              2 N +! ( leaves 5 in N )
  228.                     ( equivalent to  N @ 2 + N ! )
  229.       
  230.       , ( value -- )  put